#include "MoveAction.hpp"

MoveAction::MoveAction(Map* map, sf::Rect<int> src, sf::Rect<int> dest){
    desc = "Moved (" + StringHelper::itos(src.left) + "," + StringHelper::itos(src.top) + ")(" + StringHelper::itos(src.width) + "x" + StringHelper::itos(src.height) + ") to (" +
        StringHelper::itos(dest.left) + "," + StringHelper::itos(dest.top) + ")";
    performed = false;
    source = src;
    destination = dest;
    target = map;
    perform();
}

void MoveAction::perform(){
    if(performed){
        //Loop through all tiles that need to be changed and change them.
        for(int i = 0; i < tiles.size(); i++){
            target->tiles[tiles.at(i).tile][tiles.at(i).layer] = tiles.at(i).val;
        }
    }else{
        performed = true;

        //Here we will create a list of all tiles that need to be changed,
        //first starting with the source tiles and then destination tiles.
        //We will store pre and after information for each tile.

        //Loop through all source area tiles and create list of what needs to be changed.
        for(int l = 0; l < LAYERS; l++){
            for(int r = 0; r < source.height; r++){
                for(int c = 0; c < source.width; c++){
                    //Check that source tile is inside the map.
                    if(source.left + c >= 0 && source.left + c < target->width
                            && source.top + r >= 0 && source.top + r < target->height){
                        
                        int tile = c + source.left + (source.top + r)*target->width;
                        if(target->tiles[tile][l] != NO_SPRITE){
                            int sourceTile =  target->tiles[tile][l];
                            TileChanged changeTile;
                            changeTile.tile = tile;
                            changeTile.layer = l;
                            changeTile.original = sourceTile;
                            changeTile.val = NO_SPRITE;
                            tiles.push_back(changeTile);
                        }
                    }
                }
            }
        }

        //Loop through all destination tiles and create list of what needs to be changed.
        for(int l = 0; l < LAYERS; l++){
            for(int r = 0; r < source.height; r++){
                for(int c = 0; c < source.width; c++){
                    //Check that source tile is in map.
                    if(source.left + c >= 0 && source.left + c < target->width
                            && source.top + r >= 0 && source.top + r < target->height){
                        int tile = c + source.left + (source.top + r)*target->width;
                        //Check that destination tile is in map.
                        if(destination.left + c >= 0 && destination.left + c < target->width
                            && destination.top + r >= 0 && destination.top + r < target->height){
                            int dest = c + destination.left + (destination.top + r)*target->width;

                            if(target->tiles[tile][l] != NO_SPRITE){
                                TileChanged destTile;
                                destTile.tile = dest;
                                destTile.layer = l;
                                destTile.original = target->tiles[dest][l];
                                destTile.val = target->tiles[tile][l];
                                tiles.push_back(destTile);
                            }
                        }
                    }
                }
            }
        }

        //Having generated the lists we can perform the changes.
        perform();
    }
}

void MoveAction::undo(){
    //Loop through all tiles that need to be changed and set them to original values.
    for(int i = 0; i < tiles.size(); i++){
        target->tiles[tiles.at(i).tile][tiles.at(i).layer] = tiles.at(i).original;
    }
}

MoveAction::~MoveAction(){

}